home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / netprog.zip / NETPROG.TAR / tftp / sendrecv.c < prev    next >
C/C++ Source or Header  |  1989-12-17  |  13KB  |  515 lines

  1. /*
  2.  * Send and receive packets.
  3.  */
  4.  
  5. #include    "defs.h"
  6. #include    <sys/stat.h>
  7. #include    <ctype.h>
  8.  
  9. #ifdef    CLIENT
  10.  
  11. /*
  12.  * Send a Read-Request or a Write-Request to the other system.
  13.  * These two packets are only sent by the client to the server.
  14.  * This function is called when either the "get" command or the
  15.  * "put" command is executed by the user.
  16.  */
  17.  
  18. send_RQ(opcode, fname, mode)
  19. int    opcode;        /* OP_RRQ or OP_WRQ */
  20. char    *fname;
  21. int    mode;
  22. {
  23.     register int    len;
  24.     char        *modestr;
  25.  
  26.     DEBUG2("sending RRQ/WRQ for %s, mode = %d", fname, mode);
  27.  
  28.     stshort(opcode, sendbuff);
  29.  
  30.     strcpy(sendbuff+2, fname);
  31.     len = 2 + strlen(fname) + 1;    /* +1 for null byte at end of fname */
  32.  
  33.     switch(mode) {
  34.     case MODE_ASCII:    modestr = "netascii";    break;
  35.     case MODE_BINARY:    modestr = "octet";    break;
  36.     default:
  37.         err_dump("unknown mode");
  38.     }
  39.     strcpy(sendbuff + len, modestr);
  40.     len += strlen(modestr) + 1;    /* +1 for null byte at end of modestr */
  41.  
  42.     sendlen = len;
  43.     net_send(sendbuff, sendlen);
  44.     op_sent = opcode;
  45. }
  46.  
  47. /*
  48.  * Error packet received in response to an RRQ or a WRQ.
  49.  * Usually means the file we're asking for on the other system
  50.  * can't be accessed for some reason.  We need to print the
  51.  * error message that's returned.
  52.  * Called by finite state machine.
  53.  */
  54.  
  55. int
  56. recv_RQERR(ptr, nbytes)
  57. char    *ptr;        /* points just past received opcode */
  58. int    nbytes;        /* doesn't include received opcode */
  59. {
  60.     register int    ecode;
  61.  
  62.     ecode = ldshort(ptr);
  63.     ptr += 2;
  64.     nbytes -= 2;
  65.     ptr[nbytes] = 0;    /* assure it's null terminated ... */
  66.  
  67.     DEBUG2("ERROR received, %d bytes, error code %d", nbytes, ecode);
  68.  
  69.     fflush(stdout);
  70.     fprintf(stderr, "Error# %d: %s\n", ecode, ptr);
  71.     fflush(stderr);
  72.  
  73.     return(-1);    /* terminate finite state loop */
  74. }
  75.  
  76. #endif    /* CLIENT */
  77.  
  78. /*
  79.  * Send an acknowledgment packet to the other system.
  80.  * Called by the recv_DATA() function below and also called by
  81.  * recv_WRQ().
  82.  */
  83.  
  84. send_ACK(blocknum)
  85. int    blocknum;
  86. {
  87.     DEBUG1("sending ACK for block# %d", blocknum);
  88.  
  89.     stshort(OP_ACK, sendbuff);
  90.     stshort(blocknum, sendbuff + 2);
  91.  
  92.     sendlen = 4;
  93.     net_send(sendbuff, sendlen);
  94.  
  95. #ifdef    SORCERER
  96.     /*
  97.      * If you want to see the Sorcerer's Apprentice syndrome,
  98.      * #define SORCERER, then run this program as the client and
  99.      * get a file from a server that doesn't have the bug fixed
  100.      * (such as the 4.3BSD version).
  101.      * Turn on the trace option, and you'll see the duplicate
  102.      * data packets sent by the broken server, starting with
  103.      * block# 2.  Yet when the transfer is complete, you'll find
  104.      * the file was received correctly.
  105.      */
  106.  
  107.     if (blocknum == 1)
  108.         net_send(sendbuff, sendlen);    /* send the first ACK twice */
  109. #endif
  110.  
  111.     op_sent = OP_ACK;
  112. }
  113.  
  114. /*
  115.  * Send data to the other system.
  116.  * The data must be stored in the "sendbuff" by the caller.
  117.  * Called by the recv_ACK() function below.
  118.  */
  119.  
  120. send_DATA(blocknum, nbytes)
  121. int    blocknum;
  122. int    nbytes;        /* #bytes of actual data to send */
  123. {
  124.     DEBUG2("sending %d bytes of DATA with block# %d", nbytes, blocknum);
  125.  
  126.     stshort(OP_DATA, sendbuff);
  127.     stshort(blocknum, sendbuff + 2);
  128.  
  129.     sendlen = nbytes + 4;
  130.     net_send(sendbuff, sendlen);
  131.     op_sent = OP_DATA;
  132. }
  133.  
  134. /*
  135.  * Data packet received.  Send an acknowledgment.
  136.  * Called by finite state machine.
  137.  * Note that this function is called for both the client and the server.
  138.  */
  139.  
  140. int
  141. recv_DATA(ptr, nbytes)
  142. register char    *ptr;        /* points just past received opcode */
  143. register int    nbytes;        /* doesn't include received opcode */
  144. {
  145.     register int    recvblknum;
  146.  
  147.     recvblknum = ldshort(ptr);
  148.     ptr += 2;
  149.     nbytes -= 2;
  150.  
  151.     DEBUG2("DATA received, %d bytes, block# %d", nbytes, recvblknum);
  152.  
  153.     if (nbytes > MAXDATA)
  154.         err_dump("data packet received with length = %d bytes", nbytes);
  155.  
  156.     if (recvblknum == nextblknum) {
  157.         /*
  158.          * The data packet is the expected one.
  159.          * Increment our expected-block# for the next packet.
  160.          */
  161.  
  162.         nextblknum++;
  163.         totnbytes += nbytes;
  164.  
  165.         if (nbytes > 0) {
  166.             /*
  167.              * Note that the final data packet can have a
  168.              * data length of zero, so we only write the
  169.              * data to the local file if there is data.
  170.              */
  171.  
  172.             file_write(localfp, ptr, nbytes, modetype);
  173.         }
  174. #ifdef    SERVER
  175.         /*
  176.          * If the length of the data is between 0-511, this is
  177.          * the last data block.  For the server, here's where
  178.          * we have to close the file.  For the client, the
  179.          * "get" command processing will close the file.
  180.          */
  181.  
  182.         if (nbytes < MAXDATA)
  183.             file_close(localfp);
  184. #endif
  185.  
  186.     } else if (recvblknum < (nextblknum - 1)) {
  187.         /*
  188.          * We've just received data block# N (or earlier, such as N-1,
  189.          * N-2, etc.) from the other end, but we were expecting data
  190.          * block# N+2.  But if we were expecting N+2 it means we've
  191.          * already received N+1, so the other end went backwards from
  192.          * N+1 to N (or earlier).  Something is wrong.
  193.          */
  194.  
  195.         err_dump("recvblknum < nextblknum - 1");
  196.  
  197.     } else if (recvblknum > nextblknum) {
  198.         /*
  199.          * We've just received data block# N (or later, such as N+1,
  200.          * N+2, etc.) from the other end, but we were expecting data
  201.          * block# N-1.  But this implies that the other end has
  202.          * received an ACK for block# N-1 from us.  Something is wrong.
  203.          */
  204.  
  205.         err_dump("recvblknum > nextblknum");
  206.     }
  207.  
  208.     /*
  209.      * The only case not handled above is "recvblknum == (nextblknum - 1)".
  210.      * This means the other end never saw our ACK for the last data
  211.      * packet and retransmitted it.  We just ignore the retransmission
  212.      * and send another ACK.
  213.      *
  214.      * Acknowledge the data packet.
  215.      */
  216.  
  217.     send_ACK(recvblknum);
  218.  
  219.     /*
  220.      * If the length of the data is between 0-511, we've just
  221.      * received the final data packet, else there is more to come.
  222.      */
  223.  
  224.     return( (nbytes == MAXDATA) ? 0 : -1 );
  225. }
  226.  
  227. /*
  228.  * ACK packet received.  Send some more data.
  229.  * Called by finite state machine.  Also called by recv_RRQ() to
  230.  * start the transmission of a file to the client.
  231.  * Note that this function is called for both the client and the server.
  232.  */
  233.  
  234. int
  235. recv_ACK(ptr, nbytes)
  236. register char    *ptr;        /* points just past received opcode */
  237. register int    nbytes;        /* doesn't include received opcode */
  238. {
  239.     register int    recvblknum;
  240.  
  241.     recvblknum = ldshort(ptr);
  242.     if (nbytes != 2)
  243.         err_dump("ACK packet received with length = %d bytes",
  244.                         nbytes + 2);
  245.  
  246.     DEBUG1("ACK received, block# %d", recvblknum);
  247.  
  248.     if (recvblknum == nextblknum) {
  249.         /*
  250.          * The received acknowledgment is for the expected data
  251.          * packet that we sent.
  252.          * Fill the transmit buffer with the next block of data
  253.          * to send.
  254.          * If there's no more data to send, then we might be
  255.          * finished.  Note that we must send a final data packet
  256.          * containing 0-511 bytes of data.  If the length of the
  257.          * last packet that we sent was exactly 512 bytes, then we
  258.          * must send a 0-length data packet.
  259.          */
  260.  
  261.         if ( (nbytes = file_read(localfp, sendbuff + 4,
  262.                         MAXDATA, modetype)) == 0) {
  263.             if (lastsend < MAXDATA)
  264.                 return(-1);    /* done */
  265.             /* else we'll send nbytes=0 of data */
  266.         }
  267.  
  268.         lastsend = nbytes;
  269.         nextblknum++;        /* incr for this new packet of data */
  270.         totnbytes += nbytes;
  271.         send_DATA(nextblknum, nbytes);
  272.  
  273.         return(0);
  274.  
  275.     } else if (recvblknum < (nextblknum - 1)) {
  276.         /*
  277.          * We've just received the ACK for block# N (or earlier, such
  278.          * as N-1, N-2, etc) from the other end, but we were expecting
  279.          * the ACK for block# N+2.  But if we're expecting the ACK for
  280.          * N+2 it means we've already received the ACK for N+1, so the
  281.          * other end went backwards from N+1 to N (or earlier).
  282.          * Something is wrong.
  283.          */
  284.  
  285.         err_dump("recvblknum < nextblknum - 1");
  286.  
  287.     } else if (recvblknum > nextblknum) {
  288.         /*
  289.          * We've just received the ACK for block# N (or later, such
  290.          * as N+1, N+2, etc) from the other end, but we were expecting
  291.          * the ACK for block# N-1.  But this implies that the other
  292.          * end has already received data block# N-1 from us.
  293.          * Something is wrong.
  294.          */
  295.  
  296.         err_dump("recvblknum > nextblknum");
  297.  
  298.     } else {
  299.         /*
  300.          * Here we have "recvblknum == (nextblknum - 1)".
  301.          * This means we received a duplicate ACK.  This means either:
  302.          * (1) the other side never received our last data packet;
  303.          * (2) the other side's ACK got delayed somehow.
  304.          *
  305.          * If we were to retransmit the last data packet, we would start
  306.          * the "Sorcerer's Apprentice Syndrome."  We'll just ignore this
  307.          * duplicate ACK, returning to the FSM loop, which will initiate
  308.          * another receive.
  309.          */
  310.  
  311.         return(0);
  312.     }
  313.     /* NOTREACHED */
  314. }
  315.  
  316. #ifdef    SERVER
  317.  
  318. /*
  319.  * RRQ packet received.
  320.  * Called by the finite state machine.
  321.  * This (and receiving a WRQ) are the only ways the server gets started.
  322.  */
  323.  
  324. int
  325. recv_RRQ(ptr, nbytes)
  326. char    *ptr;
  327. int    nbytes;
  328. {
  329.     char    ackbuff[2];
  330.  
  331.     recv_xRQ(OP_RRQ, ptr, nbytes);    /* verify the RRQ packet */
  332.  
  333.     /*
  334.      * Set things up so we can just call recv_ACK() and pretend we
  335.      * received an ACK, so it'll send the first data block to the
  336.      * client.
  337.      */
  338.  
  339.     lastsend = MAXDATA;
  340.     stshort(0, ackbuff);    /* pretend its an ACK of block# 0 */
  341.  
  342.     recv_ACK(ackbuff, 2);    /* this sends data block# 1 */
  343.  
  344.     return(0);    /* the finite state machine takes over from here */
  345. }
  346.  
  347. /*
  348.  * WRQ packet received.
  349.  * Called by the finite state machine.
  350.  * This (and receiving an RRQ) are the only ways the server gets started.
  351.  */
  352.  
  353. int
  354. recv_WRQ(ptr, nbytes)
  355. char    *ptr;
  356. int    nbytes;
  357. {
  358.     recv_xRQ(OP_WRQ, ptr, nbytes);    /* verify the WRQ packet */
  359.  
  360.     /*
  361.      * Call send_ACK() to acknowledge block# 0, which will cause
  362.      * the client to send data block# 1.
  363.      */
  364.  
  365.     nextblknum = 1;
  366.     send_ACK(0);
  367.  
  368.     return(0);    /* the finite stat machine takes over from here */
  369. }
  370.  
  371. /*
  372.  * Process an RRQ or WRQ that has been received.
  373.  * Called by the 2 routines above.
  374.  */
  375.  
  376. int
  377. recv_xRQ(opcode, ptr, nbytes)
  378. int        opcode;        /* OP_RRQ or OP_WRQ */
  379. register char    *ptr;        /* points just past received opcode */
  380. register int    nbytes;        /* doesn't include received opcode */
  381. {
  382.     register int    i;
  383.     register char    *saveptr;
  384.     char        filename[MAXFILENAME], dirname[MAXFILENAME],
  385.             mode[MAXFILENAME];
  386.     struct stat    statbuff;
  387.  
  388.     /*
  389.      * Assure the filename and mode are present and
  390.      * null-terminated.
  391.      */
  392.  
  393.     saveptr = ptr;        /* points to beginning of filename */
  394.     for (i = 0; i < nbytes; i++)
  395.         if (*ptr++ == '\0')
  396.             goto FileOK;
  397.     err_dump("Invalid filename");
  398.  
  399. FileOK:
  400.     strcpy(filename, saveptr);
  401.     saveptr = ptr;        /* points to beginning of Mode */
  402.  
  403.     for ( ; i < nbytes; i++)
  404.         if (*ptr++ == '\0')
  405.             goto ModeOK;
  406.     err_dump("Invalid Mode");
  407.  
  408. ModeOK:
  409.     strlccpy(mode, saveptr);    /* copy and convert to lower case */
  410.  
  411.     if (strcmp(mode, "netascii") == 0)
  412.         modetype = MODE_ASCII;
  413.     else if (strcmp(mode, "octet") == 0)
  414.         modetype = MODE_BINARY;
  415.     else
  416.         send_ERROR(ERR_BADOP, "Mode isn't netascii or octet");
  417.  
  418.     /*
  419.      * Validate the filename.
  420.      * Note that as a daemon we might be running with root
  421.      * privileges.  Since there are no user-access checks with
  422.      * tftp (as compared to ftp, for example) we will only
  423.      * allow access to files that are publicly accessible.
  424.      *
  425.      * Also, since we're running as a daemon, our home directory
  426.      * is the root, so any filename must have it's full
  427.      * pathname specified (i.e., it must begin with a slash).
  428.      */
  429.  
  430.     if (filename[0] != '/')
  431.         send_ERROR(ERR_ACCESS, "filename must begin with '/'");
  432.  
  433.     if (opcode == OP_RRQ) {
  434.         /*
  435.          * Read request - verify that the file exists
  436.          * and that it has world read permission.
  437.          */
  438.  
  439.         if (stat(filename, &statbuff) < 0)
  440.             send_ERROR(ERR_ACCESS, sys_err_str());
  441.         if ((statbuff.st_mode & (S_IREAD >> 6)) == 0)
  442.             send_ERROR(ERR_ACCESS,
  443.                 "File doesn't allow world read permission");
  444.  
  445.     } else if (opcode == OP_WRQ) {
  446.         /*
  447.          * Write request - verify that the directory
  448.          * that the file is being written to has world
  449.          * write permission.  We've already verified above
  450.          * that the filename starts with a '/'.
  451.          */
  452.  
  453.         char    *rindex();
  454.  
  455.         strcpy(dirname, filename);
  456.         *(rindex(dirname, '/') + 1) = '\0';
  457.         if (stat(dirname, &statbuff) < 0)
  458.             send_ERROR(ERR_ACCESS, sys_err_str());
  459.         if ((statbuff.st_mode & (S_IWRITE >> 6)) == 0)
  460.             send_ERROR(ERR_ACCESS,
  461.               "Directory doesn't allow world write permission");
  462.  
  463.     } else
  464.         err_dump("unknown opcode");
  465.  
  466.     localfp = file_open(filename, (opcode == OP_RRQ) ? "r" : "w", 0);
  467.     if (localfp == NULL)
  468.         send_ERROR(ERR_NOFILE, sys_err_str());    /* doesn't return */
  469. }
  470.  
  471. /*
  472.  * Send an error packet.
  473.  * Note that an error packet isn't retransmitted or acknowledged by
  474.  * the other end, so once we're done sending it, we can exit.
  475.  */
  476.  
  477. send_ERROR(ecode, string)
  478. int    ecode;        /* error code, ERR_xxx from defs.h */
  479. char    *string;    /* some additional info */
  480.             /* can't be NULL, set to "" if empty */
  481. {
  482.     DEBUG2("sending ERROR, code = %d, string = %s", ecode, string);
  483.  
  484.     stshort(OP_ERROR, sendbuff);
  485.     stshort(ecode, sendbuff + 2);
  486.  
  487.     strcpy(sendbuff + 4, string);
  488.  
  489.     sendlen = 4 + strlen(sendbuff + 4) + 1;        /* +1 for null at end */
  490.     net_send(sendbuff, sendlen);
  491.  
  492.     net_close();
  493.  
  494.     exit(0);
  495. }
  496.  
  497. /*
  498.  * Copy a string and convert it to lower case in the process.
  499.  */
  500.  
  501. strlccpy(dest, src)
  502. register char    *dest, *src;
  503. {
  504.     register char    c;
  505.  
  506.     while ( (c = *src++) != '\0') {
  507.         if (isupper(c))
  508.             c = tolower(c);
  509.         *dest++ = c;
  510.     }
  511.     *dest = 0;
  512. }
  513.  
  514. #endif    /* SERVER */
  515.